package com.zdsoft.site.mina.codec;

import java.nio.charset.Charset;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.hundsun.encrypt.util.EncryptUtil;
import com.zdsoft.site.mina.model.PackageHeader;
import com.zdsoft.site.mina.p2p.P2PIoHandler;
/**
 * 接收时数据解码器
 * 解码器需要考虑数据的累积:
 * CumulativeProtocolDecoder类中的方法负责累积数据,把IP包拼装成完整的服务器端响应的数据。才能进行解包
 * @author cqyhm
 *
 */
public class P2PStringDecoder extends CumulativeProtocolDecoder{
	
	private Logger logger=LoggerFactory.getLogger(getClass());
	
    private final Charset charset;

    public P2PStringDecoder(Charset charset) {
        this.charset = charset;
    }
    public P2PStringDecoder() {
        this(Charset.defaultCharset());
    }
    
    protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
    	if(in.remaining()<57){//这里很关键,剩余长度不够包头的内容,继续接收.
    		return false;
    	}else{
			byte[] hbuff = new byte[57];
			in.mark();//标记当前位置，以便reset 
	    	in.get(hbuff);
	    	String value=new String(hbuff,charset);
	    	PackageHeader header=new PackageHeader(value);//获取头部
	    	session.setAttribute("phr",header);//头信息写入session中
	    	logger.debug("2.2.包头信息解码结果:{}",header.toValue());
	    	//如果还剩下的消息的长度和包体的长度不一致，说明还没有接收完整.返回false继续接收
			if (in.remaining() < header.getBodyLength()) {// 如果消息内容不够，则重置，相当于不读取size
				logger.debug("整包长度不足:[BufferSize={},remaining={},BodyLength={}",P2PIoHandler.BufferSize,in.remaining(),header.getBodyLength());
				in.reset();   //则重置，相当于不读取包头,size
				return false; //接收新数据，以拼凑成完整数据
			} else {
				logger.debug("整包长度足够:[BufferSize={},remaining={},BodyLength={}",P2PIoHandler.BufferSize,in.remaining(),header.getBodyLength());
				//1.2.可以增加校验参数
		    	//2.读取包体,并转换为对象(包体包含休息头和消息体)
		    	byte[] bbuff = new byte[header.getBodyLength()];
		    	in.get(bbuff);
		    	String message=new String(bbuff,charset);
		    	//如果是交换秘钥则返回的数据和发送的数据都是不加密的
		    	if("46700".equals(header.getInstrCd())){
		    		out.write(message.replaceAll("[\\n\\t\\r]", ""));
		    		return true;
		    	}
		    	//报文加密标志：使用固定的报文密钥进行全报文3-DES加密.
		    	if("2".equals(header.getFlag().substring(2))){
		    		String text=EncryptUtil.pkgDec(message, P2PIoHandler.pkgKey, P2PIoHandler.exchangeKey);
		    		logger.debug("2.3.mac检查结果:{}",header.checkMac(text));
		    		if(header.checkMac(text)){
			    		text=text.replaceAll("[\\n\\t\\r]", "");//去掉指定的字符:\t为制表符 \n为换行 \r为回车 正则表达式替换为空
			    		out.write(text); //传递解密之后的xml字符串到后面的过滤器
			    		logger.debug("2.4.包体信息解码并解密结果:{}",text);
		    		}else{
		    			logger.debug("mac检查结果为false,无法解析需要交换秘钥");
		    		}
		    	}else if("1".equals(header.getFlag().substring(2))){
		    	//使用固定的报文密钥进行全报文DES加密.
		    		
		    	}else {
		    		out.write(message);
				}
		    	return true;// 这里有两种情况1：没数据了，那么就结束当前调用，有数据就再次调用
			}
    	}
	}
}
